/*
 * Copyright 2010 - Jeremie Brebec
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.jb.sharedbills.server;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.jb.sharedbills.server.model.EventAccess;
import org.jb.sharedbills.server.model.EventMessage;
import org.jb.sharedbills.server.modules.Memcache;
import org.jb.sharedbills.shared.dto.Message;
import org.jb.sharedbills.shared.svc.MessageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.users.User;
import com.google.inject.Inject;
import com.google.inject.Provider;

/**
 * 
 * @author jeremie
 *
 */
public class MessageServiceImpl implements MessageService {

	private final Provider<EntityManager> emf;
	
	private final Map<Object,Object> cache;
	
	private final Provider<User> userProvider;
	
	/**
	 * 
	 * @param emf
	 */
	@Inject
	public MessageServiceImpl( Provider<EntityManager> emf, @Memcache Map<Object,Object> cache, Provider<User> user ) {
		this.emf = emf;
		this.cache = cache;
		this.userProvider = user;
	}
	
	/*
	 * 
	 */
	private String getCacheKey(String eventId) {
		return "MSG/" + eventId;
	}
	
	/**
	 * 
	 */
	@SuppressWarnings("unchecked")
	@Override
	public ArrayList<Message> getMessages(String eventId) {
		
		String cacheKey = getCacheKey(eventId);
		
		if (cache.containsKey(cacheKey)) {
			return (ArrayList<Message>)cache.get(cacheKey);
		}
		
		ArrayList<Message> messages = new ArrayList<Message>();
		
		EntityManager em = emf.get();
		try {
			
			Key key = KeyFactory.createKey( EventAccess.class.getSimpleName(), eventId );
			
			Query query = em.createQuery("SELECT m FROM " + EventMessage.class.getName() + " m WHERE m.eventKey=:key ORDER BY m.date DESCENDING" );
			query.setParameter("key", key);
			List<EventMessage> eventMessages = query.getResultList();
			
			for( EventMessage eventMessage : eventMessages ) {
				Message msg = new Message();
				msg.setFrom( eventMessage.getFrom() );
				msg.setDate( eventMessage.getDate() );
				msg.setMessage( eventMessage.getMessage());
				
				messages.add( msg );
			}
				
		} finally {		
			em.close();
		}
		
		cache.put( cacheKey, messages);
		
		return messages;
	}

	/**
	 * 
	 */
	@Override
	public void postMessage(String eventId, Message message) {
		
		if ("demo".equals(eventId))
			return;
		
		if (message.getMessage().contains("<script") || message.getFrom().isEmpty())
			throw new IllegalArgumentException("Invalid message");
		
		EntityManager em = emf.get();
		try
		{
			Key key = KeyFactory.createKey( EventAccess.class.getSimpleName(), eventId );
			EventAccess event = em.find(EventAccess.class, key);
			
			if (event == null)
				throw new IllegalArgumentException("Event not found");

			em.getTransaction().begin();
			
			EventMessage msg = new EventMessage();
			msg.setFrom( message.getFrom() );
			msg.setDate( new Date() );
			msg.setMessage( message.getMessage() );
			
			User user = userProvider.get();
			if (user != null)
				msg.setFromEmail( user.getEmail() );
			
			event.getMessages().add( msg );
			
			em.getTransaction().commit();
			
			cache.remove( getCacheKey(eventId) );
		}
		catch( Exception e ) {
			logger.error("Error adding message", e );
			throw new IllegalStateException(e);
		}
		finally
		{
			if (em.getTransaction().isActive())
				em.getTransaction().rollback();
			em.close();
		}
		
	}

	private static Logger logger = LoggerFactory.getLogger(MessageServiceImpl.class);
}
